﻿// demon8-类和对象-4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

//初始化列表：以一个冒号:开始，接着以逗号,分隔开的数据列表
// Date()
// :成员变量(初始值)
// ,成员变量(初始值)
// ,成员变量(初始值)
// {}

/*
#include <iostream>
using namespace  std;

class A
{
public:
    A(int ax, int bx)                            //初始化列表,这里没有默认构造
        :a(ax)
        ,b(bx)
    {
        cout << "A(int a = 0)" << endl;
    }
private:
    int a;
    int b;
};

class Date
{
public:
    //初始化列表,是每个成员变量初始化的位置,原则上，能用初始化列表初始化成员就直接用，而不是下面的函数体赋值修改来初始化
    Date(int year, int month,int day,int& x)
        :_n(1)
        ,_year(year)
        ,_month(2)        //但是_month不会用地下的缺省值1，因为这里给了2，没有给定值则会自动调用缺省值
        ,_day(day)
        ,_ref(x)
        //,_year(year)   //规定一个变量只能出现一次
        ,_aa(1,2)        //()里面是参数
    {
        //这里是赋值修改，先走上面的初始化列表，再走这里
        flag = 0;
        _month = month;
    }

private:
    //声明
    int _year=1;           //这里的1赋值给_year,1是缺省值，是给初始化列表用的
    int _month=1;
    int _day;
    //下边的表达式必须走初始化列表
    int flag;
    const int _n;                  //const成员变量
    int& _ref;                     //引用成员变量
    A _aa;                         //自定义类型成员变量，以上三种都需要走初始化列表，其他成员既能在初始化列表也可以在函数体初始化
};

int main()
{
    int x = 10;
    Date d1(2024, 9, 25,x);

    return 0;
}
*/


//正确使用初始化列表

/*
#include<iostream>
using namespace std;

class A
{
public:
    A(int _a,int _b)
        :a(_a)
        ,b(_b)
    {
        cout << " A(int _a,int _b)" << endl;
    }
private:
    int a;
    int b;
};

class Date
{
public:
    Date(int year, int month, int day, int& x)                //初始化列表
        :_n(1)
        ,_year(year)
        ,_month(month)
        ,_day(day)
        ,_ref(x)
        ,_aa(1,2)
        ,_p((int*)malloc(sizeof(int)*10))
    {
        //.....
        if (_p == nullptr)
        {
            perror("malloc fail");
        }
        for (size_t i = 0; i < sizeof(int)*10; i++)
        {
            //..........
        }
    }
private:
    int _year;
    int _month;
    int _day;
    const int _n;
    int& _ref;
    A _aa;
    int* _p;
};
int main()
{
    int x = 100;
    Date d1(2024, 9, 25, x);
    return 0;
}

*/


#include<iostream>
using namespace std;
class A
{
public:
    A(int x=0)
        :_x(x)
    {}

private:
    int _x;
};

A xx(1);               

class B
{
public:
    explicit B(int a=1)                               //不想发生隐式类型转换加关键字：explicit
        :_a(0)
    {}
    void Push_B(const B& bb)                        
    {
        cout << "调用 void Push_B(const B& bb):" << endl;
    }
private:                              //缺省值
    int _a = 1;
    int* _p1 = nullptr;
    int* _p2 = (int*)malloc(sizeof(int) * 10);
    A aa_1 = xx;                   //这样写过于繁琐，还需要定义一个全局的对象 A xx(1);   
    A aa_2 = 2;                    //直接这样,
};

class Date
{
public:
    Date(int year=1)
        :_year(year)
    {}
    void Push(const Date& d)
    {
        cout << "调用 void Push(const Date& d):" << endl;
    }
private:
    int _year;
};

class C
{
public:
    C(int year = 1, int month = 1,int day=1)
        :_year(year)
        ,_month(month)
        ,_day(day)
    {}
    void Push_c(const C& c)
    {
        cout << _year << "-" << _month << "-" << _day << endl;
        cout << "调用void Push(const C& c):" << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    A aa1(1);                    //拷贝构造
    A aa2 = 2;          //也是拷贝构造，单参数的构造函数支持隐式类型的转换，本质是2构造一个临时对象再进行拷贝构造
                        //这里同一表达式的连续步骤的构造，一般会被合二为一，即直接构造
    //A& aa3=3;         //这样写会报错，因为3市场里
    const A& aa3 = 3;   //因为类型转换会产生临时变量，而临时变量具有有常性，需要用const修饰，aa3引用的是3的临时变量
    B bb;
    Date d1;
    d1.Push(4);         //直接传常数调用即可，因为是单参数的构造函数支持隐式类型的转换
    cout << endl;

    //多参数的隐式类型转换
    C cc1 = {2024,9,25};
    const C& cc2 = { 2024,9,26 };
    cc1.Push_c(1);

    //如果不想发生单参数隐式类型的转换需要加关键字：explicit
    B bb2;
    //bb2.Push_B(3);      //加了explicit关键字，这行代码就报错了
    return 0;
}